/**
 * 
 */
package hw2.cs236369.tests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import hw2.cs236369.interfaces.IAuthor;
import hw2.cs236369.interfaces.IPaper;
import hw2.cs236369.parsing.Author;
import hw2.cs236369.parsing.DBLPHandler;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

import org.junit.Before;
import org.junit.Test;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;


/**
 * @author gil
 * 
 */
public class DBLPHandlerTest {
	private DBLPHandler	handler;
	private XMLReader	reader;
	private InputSource	source;

	/**
	 * Setup reader and XML input source.
	 */
	@Before
	public void setUp() throws Exception {
		reader = XMLReaderFactory.createXMLReader();
		reader.setFeature("http://xml.org/sax/features/validation", false);
		source = new InputSource(
				new StringReader(
						"<root><article><author>Author1</author><author>Author2</author><title>Article1</title><year>2012</year></article>"
								+ "<www><author>Author2</author><author>Author3</author><title>Article2</title><year>2010</year></www>"
								+ "<article><author>Name1</author><author>Name2</author><author>Author3</author><title>Article3</title></article>"
								+ "<book><author>Name1</author><author>Name2</author><author>Author3</author><title>Article3</title><year>2000</year><year>1999</year></book></root>"));
	}

	/**
	 * Tests getAuthors with regex="Author1". Verifies that only Author1
	 * returns.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetAuthor1() throws IOException, SAXException {
		handler = new DBLPHandler("Author1");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(1, c.size());
		assertEquals("Author1", c.iterator().next().getName());
	}

	/**
	 * Tests getAuthors with regex=".*". Verifies that all authors return.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetAllAuthors() throws IOException, SAXException {
		Collection<IAuthor> expected = new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"), new Author("Author3"),
				new Author("Name1"), new Author("Name2")));
		handler = new DBLPHandler(".*");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(5, c.size());
		assertTrue(expected.containsAll(c));
		assertTrue(c.containsAll(expected));
	}

	/**
	 * Tests getAuthors with regex="Author.". Verifies that only authors with
	 * "Author" prefix return.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetAuthors() throws IOException, SAXException {
		Collection<IAuthor> expected = new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"), new Author("Author3")));
		handler = new DBLPHandler("Author.");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(3, c.size());
		assertTrue(expected.containsAll(c));
		assertTrue(c.containsAll(expected));
	}

	/**
	 * Tests getAuthors with regex="Name.". Verifies that only authors with
	 * "Name" prefix return.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetNames() throws IOException, SAXException {
		Collection<IAuthor> expected = new ArrayList<IAuthor>(Arrays.asList(new Author("Name1"), new Author("Name2")));
		handler = new DBLPHandler("Name.");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(2, c.size());
		assertTrue(expected.containsAll(c));
		assertTrue(c.containsAll(expected));
	}

	/**
	 * Tests getAuthors with regex=".*1". Verifies that only authors with suffix
	 * of "1" return.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetNum() throws IOException, SAXException {
		Collection<IAuthor> expected = new ArrayList<IAuthor>(Arrays.asList(new Author("Name1"), new Author("Author1")));
		handler = new DBLPHandler(".*1");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(2, c.size());
		assertTrue(expected.containsAll(c));
		assertTrue(c.containsAll(expected));
	}

	/**
	 * Tests getAuthors with regex="x". Verifies that no authors matched
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetNoAuthors() throws IOException, SAXException {
		handler = new DBLPHandler("x");
		reader.setContentHandler(handler);
		reader.parse(source);
		Collection<IAuthor> c = handler.getAuthors();
		assertEquals(0, c.size());
	}

	/**
	 * Tests getAuthorsPapers and verifies the results.
	 * 
	 * @throws IOException
	 * @throws SAXException
	 */
	@Test
	public void testGetAuthorsPapers() throws IOException, SAXException {
		//regex = ".*1" => Author1, Name1 should be parsed.
		handler = new DBLPHandler(".*1");
		reader.setContentHandler(handler);
		reader.parse(source);
		//get Author1's papers
		Collection<IPaper> c = handler.getAuthorsPapers(new Author("Author1"));
		//verify that the only valid paper is in the results
		assertEquals(1, c.size());
		assertEquals(2012, c.iterator().next().getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"))), c.iterator().next().getAuthors());
		//get Name1's papers
		c = handler.getAuthorsPapers(new Author("Name1"));
		//verify that the only valid paper is in the results
		assertEquals(1, c.size());
		assertEquals(2000, c.iterator().next().getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Name1"), new Author("Name2"), new Author("Author3"))), c.iterator().next()
				.getAuthors());

		//regex = ".*" => Every author should be parsed.
		source = new InputSource(
				new StringReader(
						"<root><article><author>Author1</author><author>Author2</author><title>Article1</title><year>2012</year></article>"
								+ "<www><author>Author2</author><author>Author3</author><title>Article2</title><year>2010</year></www>"
								+ "<book><author>Name1</author><author>Name2</author><author>Author3</author><title>Article3</title><year>2000</year></book></root>"));
		handler = new DBLPHandler(".*");
		reader.setContentHandler(handler);
		reader.parse(source);
		//get Author1's papers
		c = handler.getAuthorsPapers(new Author("Author1"));
		//verify that the only valid paper is in the results (same as before)
		assertEquals(1, c.size());
		assertEquals(2012, c.iterator().next().getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"))), c.iterator().next().getAuthors());
		//get Author2's papers
		c = handler.getAuthorsPapers(new Author("Author2"));
		//Author2 has 2 papers. verify the results:
		assertEquals(2, c.size());
		Iterator<IPaper> it = c.iterator();
		IPaper p = it.next();
		assertEquals(2012, p.getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"))), p.getAuthors());
		p = it.next();
		assertEquals(2010, p.getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Author2"), new Author("Author3"))), p.getAuthors());

		//regex = "Author1" => Only Author1 should be parsed.
		source = new InputSource(
				new StringReader(
						"<root><article><author>Author1</author><author>Author2</author><title>Article1</title><year>2012</year></article>"
								+ "<www><author>Author2</author><author>Author3</author><title>Article2</title><year>2010</year></www>"
								+ "<book><author>Name1</author><author>Name2</author><author>Author3</author><title>Article3</title><year>2000</year></book></root>"));
		handler = new DBLPHandler("Author1");
		reader.setContentHandler(handler);
		reader.parse(source);
		//get Author1's papers
		c = handler.getAuthorsPapers(new Author("Author1"));
		//verify that the only valid paper is in the results (same as before)
		assertEquals(1, c.size());
		assertEquals(2012, c.iterator().next().getPublicationYear());
		assertEquals(new ArrayList<IAuthor>(Arrays.asList(new Author("Author1"), new Author("Author2"))), c.iterator().next().getAuthors());
		//get Author2's papers
		c = handler.getAuthorsPapers(new Author("Author2"));
		//Author2 doesnt match the regex and should not be parsed. verify null:
		assertEquals(0, c.size());
	}

}
